package tests;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;
import realDeal.BRICK;
import realDeal.Statistics;

public class basicTest {

	BRICK  testModeBrick;
	
	//parameters
	int[] stepWidths= { 10, 5, 4 ,3};
	int[] stepLengths = { 9, 5, 3,2};
	static final int numOfObjects = 10000; 
	
	@Before
	public void initial(){
		
		int totalWidth=0;
		for(int i=0;i<stepWidths.length;i++){
			totalWidth+=stepWidths[i];
		}
		
		int maxInc=1<<totalWidth;
		int numOfSteps = stepWidths.length;
		testModeBrick = new BRICK(maxInc, numOfObjects, numOfSteps, stepLengths,
				stepWidths,true);
	}
	
	//increments every counter once
	@Test
	public void incrementTest1() {
		for (int j = 0; j < numOfObjects - 1; j++) {
			testModeBrick.increment(j);
		}
		
		for (int j = 0; j < numOfObjects - 1; j++) {
			System.out.println(testModeBrick.lookup(j));
			assertEquals(testModeBrick.lookup(j),1);
		}
		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),0);
		assertEquals(stat.getUsedBuckets(),stat.getAmountOfBuckets());
	}
	//increments every counter twice
	@Test
	public void incrementTest2() {
		for (int j = 0; j < numOfObjects - 1; j++) {
			testModeBrick.increment(j);
		}
		for (int j = 0; j < numOfObjects - 1; j++) {
			assertEquals(testModeBrick.lookup(j),1);
		}
		for (int j = 0; j < numOfObjects - 1; j++) {
			testModeBrick.increment(j);
		}
		for (int j = 0; j < numOfObjects - 1; j++) {
			assertEquals(testModeBrick.lookup(j),2);
		}
		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),0);
		assertEquals(stat.getUsedBuckets(),stat.getAmountOfBuckets());
	}
	
	//increment counters in the same bucket - 1 overflow in the second step
	@Test
	public void overflowTest1() {
		int firstStepSize=1<<stepWidths[0];
		for(int i=0;i<=stepLengths[1];i++){
			for (int j = 0; j < firstStepSize+1 ; j++) {
				testModeBrick.increment(i);
			}
		}
		
		int i;				
		for(i=0;i<=stepLengths[1];i++){
			assertEquals(testModeBrick.lookup(i),firstStepSize+1);
		}
		assertEquals(testModeBrick.lookup(i),0);
		
		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),1);
		assertEquals(stat.getUsedBuckets(),1);
	}
	
	//increment counters in 2 different buckets - 0 overflows 
	@Test
	public void overflowTest2() {
		int firstStepSize=1<<stepWidths[0];
		for (int j = 0; j < stepLengths[0]-1 ; j++) {
			testModeBrick.increment(j);
		}
		for (int j = 0; j < firstStepSize+1 ; j++) {
			testModeBrick.increment(stepLengths[0]-1);
			testModeBrick.increment(stepLengths[0]);
		}
		assertEquals(testModeBrick.lookup(stepLengths[0]-1),firstStepSize+1);
		assertEquals(testModeBrick.lookup(stepLengths[0]),firstStepSize+1);
		
		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),0);
		assertEquals(stat.getUsedBuckets(),2);
	}
	
	//increment counters in the same bucket - 1 overflow in the last step
	@Test
	public void overflowTest3() {
		int sizeSum=0;
		for(int i=0;i<stepWidths.length-1;i++){
			sizeSum+=stepWidths[i];
		}
		int totalStepSize=1<<(sizeSum);
		
		for(int i=0;i<=stepLengths[stepLengths.length-1];i++){
			for (int j = 0; j < totalStepSize+1 ; j++) {
				testModeBrick.increment(i);
			}
		}
		int i;
		for(i=0;i<=stepLengths[stepLengths.length-1];i++){
			assertEquals(testModeBrick.lookup(i),totalStepSize+1);
		}
		assertEquals(testModeBrick.lookup(i),0);
		
		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),1);
		assertEquals(stat.getUsedBuckets(),1);
	}
	
	//increment counters in 3 different buckets - 3 overflows, 2 in the second step and 1 in the last
	@Test
	public void overflowTest4() {
		int firstStepSize=1<<(stepWidths[0]);
		int sizeSum=0;
		for(int i=0;i<stepWidths.length-1;i++){
			sizeSum+=stepWidths[i];
		}
		int totalStepSize=1<<(sizeSum);
		
		int i;
		for(i=0;i<=stepLengths[1];i++){
			for (int j = 0; j < firstStepSize+1 ; j++) {
				testModeBrick.increment(i);
			}
		}
		for (int j = i; j < stepLengths[0] ; j++) {
			testModeBrick.increment(i++);
		}
		for(;i<=stepLengths[0]+stepLengths[1];i++){
			for (int j = 0; j < firstStepSize+1 ; j++) {
				testModeBrick.increment(i);
			}
		}
		for (int j = i; j < 2*stepLengths[0] ; j++) {
			testModeBrick.increment(i++);
		}
		
		for(;i<=2*stepLengths[0]+stepLengths[stepLengths.length-1];i++){
			for (int j = 0; j < totalStepSize+1 ; j++) {
				testModeBrick.increment(i);
			}
		}
		
		
		for(i=0;i<=stepLengths[1];i++){
			assertEquals(testModeBrick.lookup(i),firstStepSize+1);
			assertEquals(testModeBrick.lookup(stepLengths[0]+i),firstStepSize+1);
		}
		for(i=0;i<=stepLengths[stepLengths.length-1];i++){
			assertEquals(testModeBrick.lookup(2*stepLengths[0]+i),totalStepSize+1);
		}
		
		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),3);
		assertEquals(stat.getUsedBuckets(),3);
	}
	
	//increment counters in same bucket - 1 overflow  in the first step 
	@Test
	public void overflowTest5() {
		int firstStepSize=1<<stepWidths[0];
		int sizeSum=0;
		for(int i=0;i<stepWidths.length-1;i++){
			sizeSum+=stepWidths[i];
		}
		int totalStepSize=1<<(sizeSum);
		
		for (int j = 0; j < totalStepSize+1 ; j++) {
			testModeBrick.increment(0);
		}
		for(int i=1;i<=stepLengths[1];i++){
			for (int j = 0; j < firstStepSize+1 ; j++) {
				testModeBrick.increment(i);
			}
		}
		testModeBrick.increment(0);
		
		assertEquals(testModeBrick.lookup(0),totalStepSize+2);
		assertEquals(testModeBrick.lookup(1),firstStepSize+1);
		assertEquals(testModeBrick.lookup(2),firstStepSize+1);
		

		Statistics stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),1);
		assertEquals(stat.getUsedBuckets(),1);
	}
	
	
	//increment counters in all the buckets - all buckets overflows in the first step
	@Test
	public void allBucketsOverFlowTest1() {
		int firstStepSize=1<<stepWidths[0];
		Statistics stat=testModeBrick.close();
		int numOfBuckets=stat.getAmountOfBuckets();
		for(int i=0;i<numOfBuckets;i++){
			int h;
			for(h=0;h<=stepLengths[1];h++){
				for (int j = 0; j < firstStepSize+1 ; j++) {
					testModeBrick.increment(h+i*stepLengths[0]);
				}
			}
			for(;h<stepLengths[0];h++){
				testModeBrick.increment(h+i*stepLengths[0]);
			}
		}
		for(int i=0;i<numOfBuckets;i++){
			for(int j=0;j<=stepLengths[1];j++){
				assertEquals(testModeBrick.lookup(j+i*stepLengths[0]),firstStepSize+1);
			}
		}
		
		stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),stat.getAmountOfBuckets());
		assertEquals(stat.getUsedBuckets(),stat.getAmountOfBuckets());
	}
/*
	//increment counters in all the buckets - all buckets overflows in the last step
	@Test
	public void allBucketsOverFlowTest2() {

		int sizeSum=0;
		for(int i=0;i<stepWidths.length-1;i++){
			sizeSum+=stepWidths[i];
		}
		int totalStepSize=1<<(sizeSum);
		
		Statistics stat=testModeBrick.close();
		int numOfBuckets=stat.getAmountOfBuckets();
		for(int i=0;i<numOfBuckets;i++){
			int h;
			for(h=0;h<=stepLengths[stepLengths.length-1];h++){
				for (int j = 0; j < totalStepSize+1 ; j++) {
					testModeBrick.increment(h+i*stepLengths[0]);
				}
			}
			for(;h<stepLengths[0];h++){
				testModeBrick.increment(h+i*stepLengths[0]);
			}
		}
		for(int i=0;i<numOfBuckets;i++){
			for(int j=0;j<=stepLengths[stepLengths.length-1];j++){
				assertEquals(testModeBrick.lookup(j+i*stepLengths[0]),totalStepSize+1);
			}
		}
		
		stat=testModeBrick.close();
		assertEquals(stat.getOverflowedBuckets(),stat.getAmountOfBuckets());
		assertEquals(stat.getUsedBuckets(),stat.getAmountOfBuckets());
	}*/

}
